package com.lapula.crazyface.util;

import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import android.content.Context;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.YuvImage;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.hardware.Camera.Size;

public class ImageUtils {
	/**
	 * decode image after setting the suitable inSampleSize
	 * 
	 * @param f
	 * @return
	 */
	public static Bitmap decodeFile(File f, int imageMaxSize) {
		Bitmap b = null;
		try {
			// Decode image size
			BitmapFactory.Options o = new BitmapFactory.Options();
			o.inJustDecodeBounds = true;

			FileInputStream fis = new FileInputStream(f);
			BitmapFactory.decodeStream(fis, null, o);
			fis.close();

			int scale = 1;
			if (o.outHeight > imageMaxSize || o.outWidth > imageMaxSize) {
				scale = (int) Math.pow(2,
						(int) Math.round(Math.log(imageMaxSize / (double) Math.max(o.outHeight, o.outWidth)) / Math.log(0.5)));
			}

			// Decode with inSampleSize
			BitmapFactory.Options o2 = new BitmapFactory.Options();
			o2.inSampleSize = scale;
			fis = new FileInputStream(f);
			b = BitmapFactory.decodeStream(fis, null, o2);
			fis.close();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (OutOfMemoryError e) {
			if (b != null && !b.isRecycled()) {
				b.recycle();
				b = null;
			}
		}
		return b;
	}

	/**
	 * save bitmap to sd card
	 * 
	 * @param mBitmap
	 * @return
	 */
	public static File saveBitmap(Bitmap mBitmap, String imagePath, int quality) {
		// if sd card exists and writable
		if (!android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) {
			return null;
		}

		// save picture
		File f = new File(imagePath);
		try {
			if (f != null && mBitmap != null) {
				f.createNewFile();
				FileOutputStream fOut = new FileOutputStream(f);
				mBitmap.compress(Bitmap.CompressFormat.JPEG, quality, fOut);
				fOut.flush();
				fOut.close();
				return f;
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * This method returns a bitmap related to drawable. It is ready to use
	 * method, you can use it by simply copying in your project.
	 * 
	 * @param drawable
	 *            Drawable resource of image
	 * @return Bitmap whose resource id was passed to method.
	 */
	public static Bitmap getBitmapFromDrawable(Drawable drawable) {
		Bitmap bitmap = null;
		try {
			BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
			bitmap = bitmapDrawable.getBitmap();

		} catch (Exception e) {
			e.printStackTrace();
		}
		return bitmap;
	}

	public static Bitmap getBitmapFromResource(Context context, int rid) {
		// return
		// getBitmapFromDrawable(context.getResources().getDrawable(rid));
		InputStream is = context.getResources().openRawResource(rid);
		BitmapFactory.Options options = new BitmapFactory.Options();
		options.inJustDecodeBounds = false;
		options.inSampleSize = 2;
		Bitmap bmp = BitmapFactory.decodeStream(is, null, options);
		return bmp;
	}

	/**
	 * scale bitmap
	 * 
	 * @param bitmap
	 * @param maxWidth
	 * @param maxHeight
	 * @return
	 */
	public static Bitmap scaleBitmap(Bitmap bitmap, int maxWidth, int maxHeight) {
		int bitmapWidth = bitmap.getWidth();
		int bitmapHeight = bitmap.getHeight();

		float scaleWidth = maxWidth / (float) bitmapWidth;
		float scaleHeight = maxHeight / (float) bitmapHeight;

		float scale = Math.min(scaleWidth, scaleHeight);
		Matrix matrix = new Matrix();
		matrix.postScale(scale, scale);

		return Bitmap.createBitmap(bitmap, 0, 0, bitmapWidth, bitmapHeight, matrix, true);
	}

	/**
	 * 将2进制流保存成图片
	 * 
	 * @param jpegData
	 * @param filePath
	 */
	public static void savePicData2File(byte[] jpegData, String filePath) {
		OutputStream os = null;
		try {
			os = new FileOutputStream(filePath);
		} catch (FileNotFoundException fe) {
			fe.printStackTrace();
		}
		if (os == null) {
			return;
		}

		BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(os);
		try {
			bufferedOutputStream.write(jpegData, 0, jpegData.length);
			bufferedOutputStream.flush();
		} catch (IOException ie) {
			ie.printStackTrace();
		}
		try {
			bufferedOutputStream.close();
			os.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	static public void encodeYUV420SP(byte[] yuv420sp, int[] argb, int width, int height) {
		final int frameSize = width * height;

		int yIndex = 0;
		int uvIndex = frameSize;

		int a, R, G, B, Y, U, V;
		int index = 0;
		for (int j = 0; j < height; j++) {
			for (int i = 0; i < width; i++) {

				a = (argb[index] & 0xff000000) >> 24; // a is not used obviously
				R = (argb[index] & 0xff0000) >> 16;
				G = (argb[index] & 0xff00) >> 8;
				B = (argb[index] & 0xff) >> 0;

				// well known RGB to YUV algorithm
				Y = ((66 * R + 129 * G + 25 * B + 128) >> 8) + 16;
				U = ((-38 * R - 74 * G + 112 * B + 128) >> 8) + 128;
				V = ((112 * R - 94 * G - 18 * B + 128) >> 8) + 128;

				// NV21 has a plane of Y and interleaved planes of VU each
				// sampled by a factor of 2
				// meaning for every 4 Y pixels there are 1 V and 1 U. Note the
				// sampling is every other
				// pixel AND every other scanline.
				yuv420sp[yIndex++] = (byte) ((Y < 0) ? 0 : ((Y > 255) ? 255 : Y));
				if (j % 2 == 0 && index % 2 == 0) {
					yuv420sp[uvIndex++] = (byte) ((V < 0) ? 0 : ((V > 255) ? 255 : V));
					yuv420sp[uvIndex++] = (byte) ((U < 0) ? 0 : ((U > 255) ? 255 : U));
				}

				index++;
			}
		}
	}

	public static Bitmap getImageFromAssetsFile(Context context, String fileName) {
		Bitmap image = null;
		AssetManager am = context.getResources().getAssets();
		try {
			InputStream is = am.open(fileName);
			image = BitmapFactory.decodeStream(is);
			is.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return image;
	}

	public static Bitmap compressImage(Bitmap image, int quality, boolean recyled) {
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		image.compress(Bitmap.CompressFormat.JPEG, quality, baos);// 质量压缩方法，这里100表示不压缩，把压缩后的数据存放到baos中
		ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());// 把压缩后的数据baos存放到ByteArrayInputStream中
		Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);// 把ByteArrayInputStream数据生成图片
		if (recyled){
			image.recycle();
		}
		return bitmap;
	}
	
	/**
	 * 
	 * @param data
	 * @param size
	 * @param config Bitmap.Config.RGB_565 for face detector. And Bitmap.Config.ARGB_8888 for surfaceview 
	 * @return
	 */
	public static Bitmap byte2Bitmap(byte[] data, Size size, Bitmap.Config config){
		final YuvImage image = new YuvImage(data, ImageFormat.NV21, size.width, size.height, null);
		ByteArrayOutputStream os = new ByteArrayOutputStream(data.length);
		if (!image.compressToJpeg(new Rect(0, 0, size.width, size.height), 100, os)) {
			return null;
		}
		BitmapFactory.Options bfo = new BitmapFactory.Options();
		bfo.inPreferredConfig = config;
		Bitmap bitmap = BitmapFactory.decodeStream(new ByteArrayInputStream(
				os.toByteArray()), null, bfo);
		
		return bitmap;
	}
	
	public static Bitmap rotateBitmap(Bitmap srcBitmap, boolean recycle, int degree) {
		if (srcBitmap != null) {
			Matrix m = new Matrix();
			try {
				m.setRotate(degree, srcBitmap.getWidth() / 2,
						srcBitmap.getHeight() / 2);
				Bitmap dstBitmap = Bitmap.createBitmap(srcBitmap, 0, 0,
						srcBitmap.getWidth(), srcBitmap.getHeight(), m, true);
				if (recycle && srcBitmap != null && !srcBitmap.isRecycled()) {
					srcBitmap.recycle();
				}
				return dstBitmap;
			} catch (Exception ex) {
				ex.printStackTrace();
			}
		}
		return srcBitmap;
	}
}
